package com.lanhao.aot.carrierintegration.cdek;

import java.awt.image.BufferedImage;
import java.io.File;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.openservices.shade.org.apache.commons.lang3.StringUtils;
import com.google.common.collect.Maps;
import com.lanhao.aot.pdfmerge.PDF2ImageUtil;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;

/**
 * https://www.yuque.com/cdek/api2/order-info
 * 
 * @author kunzhou3
 *
 */
public class CDEKUtil {
	private static final Logger LOG = LoggerFactory.getLogger(CDEKUtil.class);
//	public static final String Client_ID = "EMscd6r9JnFiQ3bLoyjJY6eM78JrJceI";
//	public static final String Secure_Password = "PjLZkKBHEiLK3YsjtNrt3TGNG0ahs3kG";
	public static final String Client_ID = "oTWqPEeXYhce5osfcyguhsRgCvx6aUI8";
	public static final String Secure_Password = "7l3e0tM7WoREMjHx1oT1DsZWC729v02k";
	// 测试环境 http://api.edu.cdek.ru/v2
	// 正式环境 http://api.cdek.ru/v2
	// 中国正式环境 https://int.cdek-express.cn/v2
	public static final String BASE_URL = "http://api.cdek.ru/v2";

	public static final String TOKEN_URL = "/oauth/token?grant_type={}&client_id={}&client_secret={}";
	public static final String ORDER_CONFIRM_URL = "/orders";

	public static final String PRINT_BARCODES_URL = "/print/barcodes";

	private static final DateTimeFormatter nowFmt = DateTimeFormatter.ofPattern("MMddHHmmss");

	public static void main(String[] args) {
		// 发件人地址和邮编
		String address = "Город Екатеринбург проспект Седова 53 кВ. 4";
		String postCode = "620090";
//		String delivery_point = "YEKB6";
		String delivery_point = "MSK589";
		createOrder(address, postCode, delivery_point, null);
//		getShipmentPoint(address, null);
		
//		getAccessToken();
		
//		getBarcodesPdf("http://api.cdek.ru/v2/print/barcodes/72753034-a081-4561-9d35-c936629f7001.pdf", null);
	}

	public static String getAccessToken() {
		String tokenUrl = BASE_URL + StrUtil.format(TOKEN_URL, "client_credentials", Client_ID, Secure_Password);
		LOG.info("[1、认证]开始请求token接口，url={}", tokenUrl);
		String respResult = HttpRequest.post(tokenUrl).execute().body();
		LOG.info("[1、认证]获取token接口结束，结果respResult={}", respResult);
		if (StringUtils.isNotBlank(respResult)) {
			JSONObject respResultObject = JSON.parseObject(respResult);
			String error = respResultObject.getString("error");
			if (StringUtils.isNotBlank(error)) {
				return StringUtils.EMPTY;
			}
			String accessToken = respResultObject.getString("access_token");
			String tokenType = respResultObject.getString("token_type");
			String expiresIn = respResultObject.getString("expires_in");
			String scope = respResultObject.getString("scope");
			String jti = respResultObject.getString("jti");
			
			LOG.info("[1、认证]accessToken={}, expiresIn={}", accessToken, expiresIn);
			return accessToken;
		}
		return StringUtils.EMPTY;
	}

	public static Map<String, String> getAuthHeader(String accessToken) {
		Map<String, String> headerMap = Maps.newHashMap();
		headerMap.put("Authorization", "Bearer " + accessToken);
		headerMap.put("Content-type", "application/json");
		return headerMap;
	}

	public static void createOrder(String address, String postCode, String deliveryPoint, Map<String, String> authHeader) {
		if (authHeader == null) {
			String accessToken = getAccessToken();
			if (StringUtils.isBlank(accessToken)) {
				return;
			}
			authHeader = getAuthHeader(accessToken);
		}
		JSONObject requestBody = new JSONObject();
		LocalDateTime now = LocalDateTime.now();
		int[] rNum = NumberUtil.generateRandomNumber(1000, 9999, 1);
		String format = now.format(nowFmt);
		String number = "CDEK" + format + rNum[0];
		requestBody.put("number", number);
		requestBody.put("width", 10);
		requestBody.put("length", 10);
		requestBody.put("height", 10);
//		String shipmentPoint = getShipmentPoint("", authHeader);
//		if (StringUtils.isBlank(shipmentPoint)) {
//			return;
//		}
//		requestBody.put("shipment_point", "NSK96");
		JSONObject fromLocation = new JSONObject();
		// TODO 换成真实的发货地址fromAddress
		fromLocation.put("postal_code", postCode);
		fromLocation.put("address", address);
		requestBody.put("from_location", fromLocation);
		requestBody.put("delivery_point", deliveryPoint);
		requestBody.put("date_invoice", DateUtil.format(new Date(), "yyyy-MM-dd"));
		JSONArray packagesArray = new JSONArray();
		JSONObject packagesObject = new JSONObject();
		packagesObject.put("number", number);
		packagesObject.put("weight", "500");
		packagesObject.put("comment", "");
		JSONArray itemsArray = new JSONArray();
		JSONObject itemObject = new JSONObject();
		itemObject.put("ware_key", "WELRV0086000627YQ");
		itemObject.put("name", "anhe");
		itemObject.put("cost", 0);
		itemObject.put("amount", 1);
		itemObject.put("weight", "500");
//		itemObject.put("weight_gross", "500");
		itemObject.put("url", "");
		JSONObject paymentObject = new JSONObject();
		paymentObject.put("value", 0);
		itemObject.put("payment", paymentObject);
		itemsArray.add(itemObject);
		packagesObject.put("items", itemsArray);
		packagesArray.add(packagesObject);
		requestBody.put("packages", packagesArray);

		JSONObject recipient = new JSONObject();
		recipient.put("name", "CDEK");
		JSONArray phoneArray = new JSONArray();
		JSONObject phoneObject = new JSONObject();
		phoneObject.put("number", "+79850867898");
		phoneArray.add(phoneObject);
		recipient.put("phones", phoneObject);
		requestBody.put("recipient", recipient);

		JSONObject sender = new JSONObject();
		sender.put("company", "Richard");
		requestBody.put("sender", sender);
		
		// 新增seller节点
		JSONObject seller = new JSONObject();
		seller.put("name", "anwar");
		requestBody.put("seller", seller);
		
		requestBody.put("tariff_code", "136");

		LOG.info("[2-下单]开始请求下单接口，请求参数orderCreateRequest={}", requestBody.toJSONString());
		String orderCreateRespBody = HttpRequest.post(BASE_URL + ORDER_CONFIRM_URL).addHeaders(authHeader)
				.body(requestBody.toJSONString()).execute().body();
		LOG.info("[2-下单]结束请求下单接口，返回结果orderCreateRespBody={}", orderCreateRespBody);
		JSONObject orderCreateRespObject = JSON.parseObject(orderCreateRespBody);
		JSONArray requestsArray = orderCreateRespObject.getJSONArray("requests");
		if (requestsArray != null && requestsArray.size() > 0) {
			JSONObject requestObject = requestsArray.getJSONObject(0);
			JSONArray errorsArray = requestObject.getJSONArray("errors");
			if (errorsArray != null) {
				LOG.info("[2-下单]接口调用失败，error={}", errorsArray.toString());
			} else {
				JSONObject orderEntityObject = orderCreateRespObject.getJSONObject("entity");
				String orderUUID = orderEntityObject.getString("uuid");
				try {
					TimeUnit.MILLISECONDS.sleep(500); // 延迟一秒等待面单结果
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				getOrderInfo(orderUUID, authHeader);
			}
		}

	}

	public static String getOrderInfo(String orderUUID, Map<String, String> authHeader) {
		if (authHeader == null) {
			String accessToken = getAccessToken();
			authHeader = getAuthHeader(accessToken);
		}
		String url = BASE_URL + ORDER_CONFIRM_URL + "/" + orderUUID;
		LOG.info("[3-下单查询]查询订单url={}，", url);
		String orderQryRespBody = HttpRequest.get(url).addHeaders(authHeader).execute().body();
		LOG.info("[3-下单查询]查询订单uuid={}的结果orderQryBody={}", orderUUID, orderQryRespBody);
		JSONObject orderQryRespObject = JSON.parseObject(orderQryRespBody);
		JSONArray requestsArray = orderQryRespObject.getJSONArray("requests");
		if (requestsArray != null && requestsArray.size() > 0) {
			JSONObject requestObject = requestsArray.getJSONObject(0);
			String state = requestObject.getString("state");
			JSONArray errorsArray = requestObject.getJSONArray("errors");
			if (errorsArray != null) {
				LOG.info("[3-下单查询]下单结果查询返回失败了，error={}", errorsArray.toString());
			} else {
				if ("SUCCESSFUL".equals(state)) {
					JSONObject orderEntityObject = orderQryRespObject.getJSONObject("entity");
					// String CDEKOrderUUID = orderEntityObject.getString("uuid");
					String CDEKNumber = orderEntityObject.getString("cdek_number");
					LOG.info("生成面单成功,单号={}", CDEKNumber);
					// 申请生成面单
					generateBarcodes(orderUUID, CDEKNumber, authHeader);
				}
			}
		}
		return orderQryRespBody;
	}

	public static String generateBarcodes(String CDEKOrderUUID, String CDEKNumber, Map<String, String> authHeader) {
		if (authHeader == null) {
			String accessToken = getAccessToken();
			authHeader = getAuthHeader(accessToken);
		}
		JSONObject requestBody = new JSONObject();
		JSONArray orderArray = new JSONArray();
		JSONObject orderObject = new JSONObject();
//		orderObject.put("order_uuid", CDEKOrderUUID);
		orderObject.put("cdek_number", CDEKNumber);
		orderArray.add(orderObject);

		requestBody.put("orders", orderArray);
		requestBody.put("copy_count", 1);
		requestBody.put("format", "A6");

		LOG.info("[4-生成面单]调用生成面单接口url={}，请求参数={}，", BASE_URL + PRINT_BARCODES_URL, requestBody.toJSONString());
		String barcodeGenRespBody = HttpRequest.post(BASE_URL + PRINT_BARCODES_URL).addHeaders(authHeader)
				.body(requestBody.toJSONString()).execute().body();
		LOG.info("[4-生成面单]调用生成面单接口返回结果barcodeGenRespBody={}", barcodeGenRespBody);

		JSONObject barcodeGenRespObject = JSON.parseObject(barcodeGenRespBody);

		JSONArray requestsArray = barcodeGenRespObject.getJSONArray("requests");
		if (requestsArray != null && requestsArray.size() > 0) {
			JSONObject requestObject = requestsArray.getJSONObject(0);
			JSONArray errorsArray = requestObject.getJSONArray("errors");
			if (errorsArray != null) {
				LOG.info("[4-生成面单]失败了，error={}", errorsArray.toString());
			} else {
				JSONObject orderEntityObject = barcodeGenRespObject.getJSONObject("entity");
				String barcodeUUID = orderEntityObject.getString("uuid");
				try {
					TimeUnit.MILLISECONDS.sleep(500); // 延迟一秒等待面单结果
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				// 获取面单
				getBarcodes(barcodeUUID, authHeader);
			}
		}
		return barcodeGenRespBody;
	}

	private static void getBarcodes(String barcodeUUID, Map<String, String> authHeader) {
		if (authHeader == null) {
			String accessToken = getAccessToken();
			authHeader = getAuthHeader(accessToken);
		}
		String url = BASE_URL + PRINT_BARCODES_URL + "/" + barcodeUUID;
		LOG.info("[5-查询面单]调用查询面单接口url={}", url);
		String barcodeQryRespBody = HttpRequest.get(url).addHeaders(authHeader).execute().body();
		LOG.info("[5-查询面单]调用返回结果barcodeQryRespBody={}", barcodeQryRespBody);

		JSONObject barcodeQryRespObject = JSON.parseObject(barcodeQryRespBody);

		JSONArray requestsArray = barcodeQryRespObject.getJSONArray("requests");
		if (requestsArray != null && requestsArray.size() > 0) {
			JSONObject requestObject = requestsArray.getJSONObject(0);
			JSONArray errorsArray = requestObject.getJSONArray("errors");
			if (errorsArray != null) {
				LOG.info("[5-查询面单]失败了，error={}", errorsArray.toString());
			} else {
				JSONObject orderEntityObject = barcodeQryRespObject.getJSONObject("entity");
				String labelUrl = orderEntityObject.getString("url");
				// 获取面单
				getBarcodesPdf(labelUrl, authHeader);
			}
		}
	}
	
	// http://api.cdek.ru/v2/print/barcodes/72753034-a081-4561-9d35-c936629f7001.pdf

	private static void getBarcodesPdf(String url, Map<String, String> authHeader) {
		if (authHeader == null) {
			String accessToken = getAccessToken();
			authHeader = getAuthHeader(accessToken);
		}
		File localFile = new File("D:/" + UUID.fastUUID().toString(true) + ".pdf");
		long writeBody = HttpRequest.get(url).addHeaders(authHeader).execute().writeBody(localFile);
		LOG.info("将返回流信息写入文件" + writeBody);
		
		// 处理合并的逻辑
		List<BufferedImage> imageList = PDF2ImageUtil.pdf2BufferedImageList(localFile);
		if(CollectionUtils.isNotEmpty(imageList)) {
			try {
				imageList.add(PDF2ImageUtil.cdekTemplateImage);
				String labelImgName = "D:/" + UUID.fastUUID().toString(true) + ".png";
				// 将多张图合并为一张图
				PDF2ImageUtil.mergeImagetogeter(new File(labelImgName), imageList, "png", "0");
				LOG.info("将多图合并labelImgName={}", labelImgName);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
				
	}

	private static String getShipmentPoint(String address, Map<String, String> authHeader) {
		if (authHeader == null) {
			String accessToken = getAccessToken();
			authHeader = getAuthHeader(accessToken);
		}
		LOG.info("开始请求地址转换address={}", address);
		String resp = HttpRequest.get(BASE_URL + "/deliverypoints?address=" + address).addHeaders(authHeader).timeout(20000)
				.execute().body();
		LOG.info("地址转换返回结果resp={}", resp);
		if (StringUtils.isNotBlank(resp)) {
			JSONArray deliveryPointsArray = JSON.parseArray(resp);
			if (deliveryPointsArray != null && deliveryPointsArray.size() > 0) {
				JSONObject deliveryPointsObject = deliveryPointsArray.getJSONObject(0);
				return deliveryPointsObject.getString("code");
			}
		}

		return StringUtils.EMPTY;
	}

}
